import socket

# very basic, blocking edb client
class Client:
	def __init__(self, servers_list):
		self.buffer = ''
		self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.server_name = servers_list[0]
		# just use first one:
		if servers_list[0].find(":") > 0:
			(self.host,self.port) = servers_list[0].split(":")
			self.port = int(self.port)
			self.socket.connect((self.host,self.port))
		else:
			print("atlasdbcli.Client missing : on host definition")
			raise Exception
		
	def query(self, preamble_query, items = None ):
		"""
		preamble_query\r\n
		<number of items>\r\n
		<first item's attribute key list>\r\n
		<first item's attribute value>\r\n
		"""
		
		if items == None:		
			cmdstr = "%s\r\n0\r\n" % ( preamble_query, )
		else:
			cmdstr = "%s\r\n%d\r\n" % ( preamble_query, len(items) )
			
			for item in items:
				item_parts = []
				for k,v in item.iteritems():
					item_parts.append( "%s %d" % ( str(k), len(str(v))) )
				cmdstr += ",".join(item_parts)
				cmdstr += "\r\n"
				for k,v in item.iteritems():
					cmdstr += "%s\r\n" % ( str(v), )
			
#		print("atlasdbcli query: "+cmdstr)
		self.sendcmd(cmdstr)
		
		return self.response()
		
		
		
	def response(self):
		result_pre = self.readline()
		icount = int(self.readline())
		items = []
		
		for i in range(icount):
			item_hdr = self.readline()
			item_attrs = item_hdr.split(",")
			attrs = {}
			for attr in item_attrs:
				key_name, value_sz = attr.split(" ")
				value_sz = int(value_sz)
				
				attrs[key_name] = self.recv_value(value_sz)
			items.append(attrs)
			
		return items
			

	def sendcmd(self,cmdstr):
		return self.socket.sendall(cmdstr)
		
	def recv_value(self, rlen):
		rlen += 2 # include \r\n
		buf = self.recv(rlen)
		if len(buf) != rlen:
			print("received %d bytes when expecting %d" % (len(buf), rlen))
			return ""
#			 raise _Error("received %d bytes when expecting %d" % (len(buf), rlen))

		if len(buf) == rlen:
			buf = buf[:-2]	# strip \r\n

		return buf

	def recv(self, rlen):
		self_socket_recv = self.socket.recv
		buf = self.buffer
		while len(buf) < rlen:
			foo = self_socket_recv(4096)
			buf += foo
			if len(foo) == 0:
				print( 'Read %d bytes, expecting %d, read returned 0 length bytes' % ( len(buf), foo ) )
				return ""
#				 raise _Error, ( 'Read %d bytes, expecting %d, '
#						 'read returned 0 length bytes' % ( len(buf), foo ))
		self.buffer = buf[rlen:]
		return buf[:rlen]
		
	def readline(self):
		buf = self.buffer
		self_socket_recv = self.socket.recv
		while True:
			index = buf.find('\r\n')
			if index >= 0:
				break
			data = self_socket_recv(4096)
			if not data:
#				 self.mark_dead('Connection closed while reading from %s'
 #						 % repr(self))
				print('Connection closed while reading from edb %s' % self.server_name)
				break
			buf += data
		if index >= 0:
			self.buffer = buf[index+2:]
			buf = buf[:index]
		else:
			self.buffer = ''
		return buf

		